home *** CD-ROM | disk | FTP | other *** search
/ Windows Expert / Windows Expert.iso / windownt / awksrc.zip / BUILTIN.C < prev    next >
C/C++ Source or Header  |  1993-09-27  |  24KB  |  1,129 lines

  1. /*
  2.  * builtin.c - Builtin functions and various utility procedures 
  3.  */
  4.  
  5. /* 
  6.  * Copyright (C) 1986, 1988, 1989, 1991, 1992 the Free Software Foundation, Inc.
  7.  * 
  8.  * This file is part of GAWK, the GNU implementation of the
  9.  * AWK Progamming Language.
  10.  * 
  11.  * GAWK is free software; you can redistribute it and/or modify
  12.  * it under the terms of the GNU General Public License as published by
  13.  * the Free Software Foundation; either version 2 of the License, or
  14.  * (at your option) any later version.
  15.  * 
  16.  * GAWK is distributed in the hope that it will be useful,
  17.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19.  * GNU General Public License for more details.
  20.  * 
  21.  * You should have received a copy of the GNU General Public License
  22.  * along with GAWK; see the file COPYING.  If not, write to
  23.  * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  24.  */
  25.  
  26.  
  27. #include "awk.h"
  28.  
  29.  
  30. #ifndef SRANDOM_PROTO
  31. extern void srandom P((int seed));
  32. #endif
  33. extern char *initstate P((unsigned seed, char *state, int n));
  34. extern char *setstate P((char *state));
  35. extern long random P((void));
  36.  
  37. extern NODE **fields_arr;
  38. extern int output_is_tty;
  39.  
  40. static NODE *sub_common P((NODE *tree, int global));
  41.  
  42. #ifdef GFMT_WORKAROUND
  43. char *gfmt P((double g, int prec, char *buf));
  44. #endif
  45.  
  46. #ifdef _CRAY
  47. /* Work around a problem in conversion of doubles to exact integers. */
  48. #include <float.h>
  49. #define Floor(n) floor((n) * (1.0 + DBL_EPSILON))
  50. #define Ceil(n) ceil((n) * (1.0 + DBL_EPSILON))
  51.  
  52. /* Force the standard C compiler to use the library math functions. */
  53. extern double exp(double);
  54. double (*Exp)() = exp;
  55. #define exp(x) (*Exp)(x)
  56. extern double log(double);
  57. double (*Log)() = log;
  58. #define log(x) (*Log)(x)
  59. #else
  60. #define Floor(n) floor(n)
  61. #define Ceil(n) ceil(n)
  62. #endif
  63.  
  64. /* Builtin functions */
  65. NODE *
  66. do_exp(tree)
  67. NODE *tree;
  68. {
  69.     NODE *tmp;
  70.     double d, res;
  71. #ifndef exp
  72.     double exp P((double));
  73. #endif
  74.  
  75.     tmp= tree_eval(tree->lnode);
  76.     d = force_number(tmp);
  77.     free_temp(tmp);
  78.     errno = 0;
  79.     res = exp(d);
  80.     if (errno == ERANGE)
  81.         warning("exp argument %g is out of range", d);
  82.     return tmp_number((AWKNUM) res);
  83. }
  84.  
  85. NODE *
  86. do_index(tree)
  87. NODE *tree;
  88. {
  89.     NODE *s1, *s2;
  90.     register char *p1, *p2;
  91.     register int l1, l2;
  92.     long ret;
  93.  
  94.  
  95.     s1 = tree_eval(tree->lnode);
  96.     s2 = tree_eval(tree->rnode->lnode);
  97.     force_string(s1);
  98.     force_string(s2);
  99.     p1 = s1->stptr;
  100.     p2 = s2->stptr;
  101.     l1 = s1->stlen;
  102.     l2 = s2->stlen;
  103.     ret = 0;
  104.     if (IGNORECASE) {
  105.         while (l1) {
  106.             if (l2 > l1)
  107.                 break;
  108.             if (casetable[(int)*p1] == casetable[(int)*p2]
  109.                 && (l2 == 1 || strncasecmp(p1, p2, l2) == 0)) {
  110.                 ret = 1 + s1->stlen - l1;
  111.                 break;
  112.             }
  113.             l1--;
  114.             p1++;
  115.         }
  116.     } else {
  117.         while (l1) {
  118.             if (l2 > l1)
  119.                 break;
  120.             if (*p1 == *p2
  121.                 && (l2 == 1 || STREQN(p1, p2, l2))) {
  122.                 ret = 1 + s1->stlen - l1;
  123.                 break;
  124.             }
  125.             l1--;
  126.             p1++;
  127.         }
  128.     }
  129.     free_temp(s1);
  130.     free_temp(s2);
  131.     return tmp_number((AWKNUM) ret);
  132. }
  133.  
  134. NODE *
  135. do_int(tree)
  136. NODE *tree;
  137. {
  138.     NODE *tmp;
  139.     double floor P((double));
  140.     double ceil P((double));
  141.     double d;
  142.  
  143.     tmp = tree_eval(tree->lnode);
  144.     d = force_number(tmp);
  145.     if (d >= 0)
  146.         d = Floor(d);
  147.     else
  148.         d = Ceil(d);
  149.     free_temp(tmp);
  150.     return tmp_number((AWKNUM) d);
  151. }
  152.  
  153. NODE *
  154. do_length(tree)
  155. NODE *tree;
  156. {
  157.     NODE *tmp;
  158.     int len;
  159.  
  160.     tmp = tree_eval(tree->lnode);
  161.     len = force_string(tmp)->stlen;
  162.     free_temp(tmp);
  163.     return tmp_number((AWKNUM) len);
  164. }
  165.  
  166. NODE *
  167. do_log(tree)
  168. NODE *tree;
  169. {
  170.     NODE *tmp;
  171. #ifndef log
  172.     double log P((double));
  173. #endif
  174.     double d, arg;
  175.  
  176.     tmp = tree_eval(tree->lnode);
  177.     arg = (double) force_number(tmp);
  178.     if (arg < 0.0)
  179.         warning("log called with negative argument %g", arg);
  180.     d = log(arg);
  181.     free_temp(tmp);
  182.     return tmp_number((AWKNUM) d);
  183. }
  184.  
  185. /* %e and %f formats are not properly implemented.  Someone should fix them */
  186. /* Actually, this whole thing should be reimplemented. */
  187.  
  188. NODE *
  189. do_sprintf(tree)
  190. NODE *tree;
  191. {
  192. #define bchunk(s,l) if(l) {\
  193.     while((l)>ofre) {\
  194.       erealloc(obuf, char *, osiz*2, "do_sprintf");\
  195.       ofre+=osiz;\
  196.       osiz*=2;\
  197.     }\
  198.     memcpy(obuf+olen,s,(l));\
  199.     olen+=(l);\
  200.     ofre-=(l);\
  201.   }
  202.  
  203.     /* Is there space for something L big in the buffer? */
  204. #define chksize(l)  if((l)>ofre) {\
  205.     erealloc(obuf, char *, osiz*2, "do_sprintf");\
  206.     ofre+=osiz;\
  207.     osiz*=2;\
  208.   }
  209.  
  210.     /*
  211.      * Get the next arg to be formatted.  If we've run out of args,
  212.      * return "" (Null string) 
  213.      */
  214. #define parse_next_arg() {\
  215.   if(!carg) { toofew = 1; break; }\
  216.   else {\
  217.     arg=tree_eval(carg->lnode);\
  218.     carg=carg->rnode;\
  219.   }\
  220.  }
  221.  
  222.     NODE *r;
  223.     int toofew = 0;
  224.     char *obuf;
  225.     int osiz, ofre, olen;
  226.     static char chbuf[] = "0123456789abcdef";
  227.     static char sp[] = " ";
  228.     char *s0, *s1;
  229.     int n0;
  230.     NODE *sfmt, *arg;
  231.     register NODE *carg;
  232.     long fw, prec, lj, alt, big;
  233.     long *cur;
  234.     long val;
  235. #ifdef sun386        /* Can't cast unsigned (int/long) from ptr->value */
  236.     long tmp_uval;    /* on 386i 4.0.1 C compiler -- it just hangs */
  237. #endif
  238.     unsigned long uval;
  239.     int sgn;
  240.     int base;
  241.     char cpbuf[30];        /* if we have numbers bigger than 30 */
  242.     char *cend = &cpbuf[30];/* chars, we lose, but seems unlikely */
  243.     char *cp;
  244.     char *fill;
  245.     double tmpval;
  246.     char *pr_str;
  247.     int ucasehex = 0;
  248.     char signchar = 0;
  249.     int len;
  250.  
  251.  
  252.     emalloc(obuf, char *, 120, "do_sprintf");
  253.     osiz = 120;
  254.     ofre = osiz - 1;
  255.     olen = 0;
  256.     sfmt = tree_eval(tree->lnode);
  257.     sfmt = force_string(sfmt);
  258.     carg = tree->rnode;
  259.     for (s0 = s1 = sfmt->stptr, n0 = sfmt->stlen; n0-- > 0;) {
  260.         if (*s1 != '%') {
  261.             s1++;
  262.             continue;
  263.         }
  264.         bchunk(s0, s1 - s0);
  265.         s0 = s1;
  266.         cur = &fw;
  267.         fw = 0;
  268.         prec = 0;
  269.         lj = alt = big = 0;
  270.         fill = sp;
  271.         cp = cend;
  272.         s1++;
  273.  
  274. retry:
  275.         --n0;
  276.         switch (*s1++) {
  277.         case '%':
  278.             bchunk("%", 1);
  279.             s0 = s1;
  280.             break;
  281.  
  282.         case '0':
  283.             if (fill != sp || lj)
  284.                 goto lose;
  285.             if (cur == &fw)
  286.                 fill = "0";    /* FALL through */
  287.         case '1':
  288.         case '2':
  289.         case '3':
  290.         case '4':
  291.         case '5':
  292.         case '6':
  293.         case '7':
  294.         case '8':
  295.         case '9':
  296.             if (cur == 0)
  297.                 goto lose;
  298.             *cur = s1[-1] - '0';
  299.             while (n0 > 0 && *s1 >= '0' && *s1 <= '9') {
  300.                 --n0;
  301.                 *cur = *cur * 10 + *s1++ - '0';
  302.             }
  303.             goto retry;
  304.         case '*':
  305.             if (cur == 0)
  306.                 goto lose;
  307.             parse_next_arg();
  308.             *cur = (long) force_number(arg);
  309.             free_temp(arg);
  310.             goto retry;
  311.         case ' ':        /* print ' ' or '-' */
  312.         case '+':        /* print '+' or '-' */
  313.             signchar = *(s1-1);
  314.             goto retry;
  315.         case '-':
  316.             if (lj || fill != sp)
  317.                 goto lose;
  318.             lj++;
  319.             goto retry;
  320.         case '.':
  321.             if (cur != &fw)
  322.                 goto lose;
  323.             cur = ≺
  324.             goto retry;
  325.         case '#':
  326.             if (alt)
  327.                 goto lose;
  328.             alt++;
  329.             goto retry;
  330.         case 'l':
  331.             if (big)
  332.                 goto lose;
  333.             big++;
  334.             goto retry;
  335.         case 'c':
  336.             parse_next_arg();
  337.             if (arg->flags & NUMBER) {
  338. #ifdef sun386
  339.                 tmp_uval = arg->numbr; 
  340.                 uval= (unsigned long) tmp_uval;
  341. #else
  342.                 uval = (unsigned long) arg->numbr;
  343. #endif
  344.                 cpbuf[0] = (char) uval;
  345.                 prec = 1;
  346.                 pr_str = cpbuf;
  347.                 goto dopr_string;
  348.             }
  349.             if (! prec)
  350.                 prec = 1;
  351.             else if (prec > (signed) arg->stlen)
  352.                 prec = arg->stlen;
  353.             pr_str = arg->stptr;
  354.             goto dopr_string;
  355.         case 's':
  356.             parse_next_arg();
  357.             arg = force_string(arg);
  358.             if (!prec || prec > (signed) arg->stlen)
  359.                 prec = arg->stlen;
  360.             pr_str = arg->stptr;
  361.  
  362.     dopr_string:
  363.             if (fw > prec && !lj) {
  364.                 while (fw > prec) {
  365.                     bchunk(sp, 1);
  366.                     fw--;
  367.                 }
  368.             }
  369.             bchunk(pr_str, (int) prec);
  370.             if (fw > prec) {
  371.                 while (fw > prec) {
  372.                     bchunk(sp, 1);
  373.                     fw--;
  374.                 }
  375.             }
  376.             s0 = s1;
  377.             free_temp(arg);
  378.             break;
  379.         case 'd':
  380.         case 'i':
  381.             parse_next_arg();
  382.             val = (long) force_number(arg);
  383.             free_temp(arg);
  384.             if (val < 0) {
  385.                 sgn = 1;
  386.                 val = -val;
  387.             } else
  388.                 sgn = 0;
  389.             do {
  390.                 *--cp = '0' + val % 10;
  391.                 val /= 10;
  392.             } while (val);
  393.             if (sgn)
  394.                 *--cp = '-';
  395.             else if (signchar)
  396.                 *--cp = signchar;
  397.             if (prec > fw)
  398.                 fw = prec;
  399.             prec = cend - cp;
  400.             if (fw > prec && !lj) {
  401.                 if (fill != sp && (*cp == '-' || signchar)) {
  402.                     bchunk(cp, 1);
  403.                     cp++;
  404.                     prec--;
  405.                     fw--;
  406.                 }
  407.                 while (fw > prec) {
  408.                     bchunk(fill, 1);
  409.                     fw--;
  410.                 }
  411.             }
  412.             bchunk(cp, (int) prec);
  413.             if (fw > prec) {
  414.                 while (fw > prec) {
  415.                     bchunk(fill, 1);
  416.                     fw--;
  417.                 }
  418.             }
  419.             s0 = s1;
  420.             break;
  421.         case 'u':
  422.             base = 10;
  423.             goto pr_unsigned;
  424.         case 'o':
  425.             base = 8;
  426.             goto pr_unsigned;
  427.         case 'X':
  428.             ucasehex = 1;
  429.         case 'x':
  430.             base = 16;
  431.             goto pr_unsigned;
  432.     pr_unsigned:
  433.             parse_next_arg();
  434.             uval = (unsigned long) force_number(arg);
  435.             free_temp(arg);
  436.             do {
  437.                 *--cp = chbuf[uval % base];
  438.                 if (ucasehex && isalpha(*cp))
  439.                     *cp = toupper(*cp);
  440.                 uval /= base;
  441.             } while (uval);
  442.             if (alt && (base == 8 || base == 16)) {
  443.                 if (base == 16) {
  444.                     if (ucasehex)
  445.                         *--cp = 'X';
  446.                     else
  447.                         *--cp = 'x';
  448.                 }
  449.                 *--cp = '0';
  450.             }
  451.             prec = cend - cp;
  452.             if (fw > prec && !lj) {
  453.                 while (fw > prec) {
  454.                     bchunk(fill, 1);
  455.                     fw--;
  456.                 }
  457.             }
  458.             bchunk(cp, (int) prec);
  459.             if (fw > prec) {
  460.                 while (fw > prec) {
  461.                     bchunk(fill, 1);
  462.                     fw--;
  463.                 }
  464.             }
  465.             s0 = s1;
  466.             break;
  467.         case 'g':
  468.             parse_next_arg();
  469.             tmpval = force_number(arg);
  470.             free_temp(arg);
  471.             chksize(fw + prec + 9);    /* 9==slop */
  472.  
  473.             cp = cpbuf;
  474.             *cp++ = '%';
  475.             if (lj)
  476.                 *cp++ = '-';
  477.             if (fill != sp)
  478.                 *cp++ = '0';
  479. #ifndef GFMT_WORKAROUND
  480.             if (cur != &fw) {
  481.                 (void) strcpy(cp, "*.*g");
  482.                 (void) sprintf(obuf + olen, cpbuf, (int) fw, (int) prec, (double) tmpval);
  483.             } else {
  484.                 (void) strcpy(cp, "*g");
  485.                 (void) sprintf(obuf + olen, cpbuf, (int) fw, (double) tmpval);
  486.             }
  487. #else    /* GFMT_WORKAROUND */
  488.               {
  489.             char *gptr, gbuf[120];
  490. #define DEFAULT_G_PRECISION 6
  491.             if (fw + prec + 9 > sizeof gbuf) {    /* 9==slop */
  492.                 emalloc(gptr, char *, fw+prec+9, "do_sprintf(gfmt)");
  493.             } else
  494.                 gptr = gbuf;
  495.             (void) gfmt((double) tmpval, cur != &fw ?
  496.                     (int) prec : DEFAULT_G_PRECISION, gptr);
  497.             *cp++ = '*',  *cp++ = 's',  *cp = '\0';
  498.             (void) sprintf(obuf + olen, cpbuf, (int) fw, gptr);
  499.             if (fill != sp && *gptr == ' ') {
  500.                 char *p = gptr;
  501.                 do { *p++ = '0'; } while (*p == ' ');
  502.             }
  503.             if (gptr != gbuf) free(gptr);
  504.               }
  505. #endif    /* GFMT_WORKAROUND */
  506.             len = strlen(obuf + olen);
  507.             ofre -= len;
  508.             olen += len;
  509.             s0 = s1;
  510.             break;
  511.  
  512.         case 'f':
  513.             parse_next_arg();
  514.             tmpval = force_number(arg);
  515.             free_temp(arg);
  516.             chksize(fw + prec + 9);    /* 9==slop */
  517.  
  518.             cp = cpbuf;
  519.             *cp++ = '%';
  520.             if (lj)
  521.                 *cp++ = '-';
  522.             if (fill != sp)
  523.                 *cp++ = '0';
  524.             if (cur != &fw) {
  525.                 (void) strcpy(cp, "*.*f");
  526.                 (void) sprintf(obuf + olen, cpbuf, (int) fw, (int) prec, (double) tmpval);
  527.             } else {
  528.                 (void) strcpy(cp, "*f");
  529.                 (void) sprintf(obuf + olen, cpbuf, (int) fw, (double) tmpval);
  530.             }
  531.             len = strlen(obuf + olen);
  532.             ofre -= len;
  533.             olen += len;
  534.             s0 = s1;
  535.             break;
  536.         case 'e':
  537.             parse_next_arg();
  538.             tmpval = force_number(arg);
  539.             free_temp(arg);
  540.             chksize(fw + prec + 9);    /* 9==slop */
  541.             cp = cpbuf;
  542.             *cp++ = '%';
  543.             if (lj)
  544.                 *cp++ = '-';
  545.             if (fill != sp)
  546.                 *cp++ = '0';
  547.             if (cur != &fw) {
  548.                 (void) strcpy(cp, "*.*e");
  549.                 (void) sprintf(obuf + olen, cpbuf, (int) fw, (int) prec, (double) tmpval);
  550.             } else {
  551.                 (void) strcpy(cp, "*e");
  552.                 (void) sprintf(obuf + olen, cpbuf, (int) fw, (double) tmpval);
  553.             }
  554.             len = strlen(obuf + olen);
  555.             ofre -= len;
  556.             olen += len;
  557.             s0 = s1;
  558.             break;
  559.  
  560.         default:
  561.     lose:
  562.             break;
  563.         }
  564.         if (toofew)
  565.             fatal("%s\n\t%s\n\t%*s%s",
  566.             "not enough arguments to satisfy format string",
  567.             sfmt->stptr, s1 - sfmt->stptr - 2, "",
  568.             "^ ran out for this one"
  569.             );
  570.     }
  571.     if (carg != NULL)
  572.         warning("too many arguments supplied for format string");
  573.     bchunk(s0, s1 - s0);
  574.     free_temp(sfmt);
  575.     r = make_str_node(obuf, olen, ALREADY_MALLOCED);
  576.     r->flags |= TEMP;
  577.     return r;
  578. }
  579.  
  580. void
  581. do_printf(tree)
  582. register NODE *tree;
  583. {
  584.     struct redirect *rp = NULL;
  585.     register FILE *fp;
  586.  
  587.     if (tree->rnode) {
  588.         int errflg;    /* not used, sigh */
  589.  
  590.         rp = redirect(tree->rnode, &errflg);
  591.         if (rp) {
  592.             fp = rp->fp;
  593.             if (!fp)
  594.                 return;
  595.         } else
  596.             return;
  597.     } else
  598.         fp = stdout;
  599.     tree = do_sprintf(tree->lnode);
  600.     (void) fwrite(tree->stptr, sizeof(char), tree->stlen, fp);
  601.     free_temp(tree);
  602.     if ((fp == stdout && output_is_tty) || (rp && (rp->flag & RED_NOBUF)))
  603.         fflush(fp);
  604.     if (ferror(fp)) {
  605.         warning("error writing output: %s", strerror(errno));
  606.         clearerr(fp);
  607.     }
  608. }
  609.  
  610. NODE *
  611. do_sqrt(tree)
  612. NODE *tree;
  613. {
  614.     NODE *tmp;
  615.     double arg;
  616.     extern double sqrt P((double));
  617.  
  618.     tmp = tree_eval(tree->lnode);
  619.     arg = (double) force_number(tmp);
  620.     free_temp(tmp);
  621.     if (arg < 0.0)
  622.         warning("sqrt called with negative argument %g", arg);
  623.     return tmp_number((AWKNUM) sqrt(arg));
  624. }
  625.  
  626. NODE *
  627. do_substr(tree)
  628. NODE *tree;
  629. {
  630.     NODE *t1, *t2, *t3;
  631.     NODE *r;
  632.     register int indx, length;
  633.  
  634.     t1 = tree_eval(tree->lnode);
  635.     t2 = tree_eval(tree->rnode->lnode);
  636.     if (tree->rnode->rnode == NULL)    /* third arg. missing */
  637.         length = t1->stlen;
  638.     else {
  639.         t3 = tree_eval(tree->rnode->rnode->lnode);
  640.         length = (int) force_number(t3);
  641.         free_temp(t3);
  642.     }
  643.     indx = (int) force_number(t2) - 1;
  644.     free_temp(t2);
  645.     t1 = force_string(t1);
  646.     if (indx < 0)
  647.         indx = 0;
  648.     if (indx >= (int) t1->stlen || length <= 0) {
  649.         free_temp(t1);
  650.         return Nnull_string;
  651.     }
  652.     if (indx + length > (int) t1->stlen)
  653.         length = t1->stlen - indx;
  654.     r =  tmp_string(t1->stptr + indx, length);
  655.     free_temp(t1);
  656.     return r;
  657. }
  658.  
  659. NODE *
  660. do_strftime(tree)
  661. NODE *tree;
  662. {
  663.     NODE *t1, *t2;
  664.     struct tm *tm;
  665.     time_t fclock;
  666.     char buf[100];
  667.     int ret;
  668.  
  669.     t1 = force_string(tree_eval(tree->lnode));
  670.  
  671.     if (tree->rnode == NULL)    /* second arg. missing, default */
  672.         (void) time(&fclock);
  673.     else {
  674.         t2 = tree_eval(tree->rnode->lnode);
  675.         fclock = (time_t) force_number(t2);
  676.         free_temp(t2);
  677.     }
  678.     tm = localtime(&fclock);
  679.  
  680.     ret = strftime(buf, 100, t1->stptr, tm);
  681.  
  682.     return tmp_string(buf, ret);
  683. }
  684.  
  685. NODE *
  686. do_systime(tree)
  687. NODE *tree;
  688. {
  689.     time_t lclock;
  690.  
  691.     (void) time(&lclock);
  692.     return tmp_number((AWKNUM) lclock);
  693. }
  694.  
  695. NODE *
  696. do_system(tree)
  697. NODE *tree;
  698. {
  699.     NODE *tmp;
  700.     int ret = 0;
  701.     char *cmd;
  702.  
  703.     (void) flush_io ();    /* so output is synchronous with gawk's */
  704.     tmp = tree_eval(tree->lnode);
  705.     cmd = force_string(tmp)->stptr;
  706.     if (cmd && *cmd) {
  707.         ret = system(cmd);
  708.         ret = (ret >> 8) & 0xff;
  709.     }
  710.     free_temp(tmp);
  711.     return tmp_number((AWKNUM) ret);
  712. }
  713.  
  714. void 
  715. do_print(tree)
  716. register NODE *tree;
  717. {
  718.     register NODE *t1;
  719.     struct redirect *rp = NULL;
  720.     register FILE *fp;
  721.     register char *s;
  722.  
  723.     if (tree->rnode) {
  724.         int errflg;        /* not used, sigh */
  725.  
  726.         rp = redirect(tree->rnode, &errflg);
  727.         if (rp) {
  728.             fp = rp->fp;
  729.             if (!fp)
  730.                 return;
  731.         } else
  732.             return;
  733.     } else
  734.         fp = stdout;
  735.     tree = tree->lnode;
  736.     while (tree) {
  737.         t1 = tree_eval(tree->lnode);
  738.         if (t1->flags & NUMBER) {
  739.             if (OFMTidx == CONVFMTidx)
  740.                 (void) force_string(t1);
  741.             else {
  742.                 char buf[100];
  743.  
  744.                 sprintf(buf, OFMT, t1->numbr);
  745.                 t1 = tmp_string(buf, strlen(buf));
  746.             }
  747.         }
  748.         (void) fwrite(t1->stptr, sizeof(char), t1->stlen, fp);
  749.         free_temp(t1);
  750.         tree = tree->rnode;
  751.         if (tree) {
  752.             s = OFS;
  753. #if (!defined(VMS)) || defined(NO_TTY_FWRITE)
  754.             while (*s)
  755.                 putc(*s++, fp);
  756. #else
  757.             if (OFSlen)
  758.                 (void) fwrite(s, sizeof(char), OFSlen, fp);
  759. #endif    /* VMS && !NO_TTY_FWRITE */
  760.         }
  761.     }
  762.     s = ORS;
  763. #if (!defined(VMS)) || defined(NO_TTY_FWRITE)
  764.     while (*s)
  765.         putc(*s++, fp);
  766.     if ((fp == stdout && output_is_tty) || (rp && (rp->flag & RED_NOBUF)))
  767. #else
  768.     if (ORSlen)
  769.         (void) fwrite(s, sizeof(char), ORSlen, fp);
  770.     if ((rp && (rp->flag & RED_NOBUF)))
  771. #endif    /* VMS && !NO_TTY_FWRITE */
  772.         fflush(fp);
  773.     if (ferror(fp)) {
  774.         warning("error writing output: %s", strerror(errno));
  775.         clearerr(fp);
  776.     }
  777. }
  778.  
  779. NODE *
  780. do_tolower(tree)
  781. NODE *tree;
  782. {
  783.     NODE *t1, *t2;
  784.     register char *cp, *cp2;
  785.  
  786.     t1 = tree_eval(tree->lnode);
  787.     t1 = force_string(t1);
  788.     t2 = tmp_string(t1->stptr, t1->stlen);
  789.     for (cp = t2->stptr, cp2 = t2->stptr + t2->stlen; cp < cp2; cp++)
  790.         if (isupper(*cp))
  791.             *cp = tolower(*cp);
  792.     free_temp(t1);
  793.     return t2;
  794. }
  795.  
  796. NODE *
  797. do_toupper(tree)
  798. NODE *tree;
  799. {
  800.     NODE *t1, *t2;
  801.     register char *cp;
  802.  
  803.     t1 = tree_eval(tree->lnode);
  804.     t1 = force_string(t1);
  805.     t2 = tmp_string(t1->stptr, t1->stlen);
  806.     for (cp = t2->stptr; cp < t2->stptr + t2->stlen; cp++)
  807.         if (islower(*cp))
  808.             *cp = toupper(*cp);
  809.     free_temp(t1);
  810.     return t2;
  811. }
  812.  
  813. NODE *
  814. do_atan2(tree)
  815. NODE *tree;
  816. {
  817.     NODE *t1, *t2;
  818.     extern double atan2 P((double, double));
  819.     double d1, d2;
  820.  
  821.     t1 = tree_eval(tree->lnode);
  822.     t2 = tree_eval(tree->rnode->lnode);
  823.     d1 = force_number(t1);
  824.     d2 = force_number(t2);
  825.     free_temp(t1);
  826.     free_temp(t2);
  827.     return tmp_number((AWKNUM) atan2(d1, d2));
  828. }
  829.  
  830. NODE *
  831. do_sin(tree)
  832. NODE *tree;
  833. {
  834.     NODE *tmp;
  835.     extern double sin P((double));
  836.     double d;
  837.  
  838.     tmp = tree_eval(tree->lnode);
  839.     d = sin((double)force_number(tmp));
  840.     free_temp(tmp);
  841.     return tmp_number((AWKNUM) d);
  842. }
  843.  
  844. NODE *
  845. do_cos(tree)
  846. NODE *tree;
  847. {
  848.     NODE *tmp;
  849.     extern double cos P((double));
  850.     double d;
  851.  
  852.     tmp = tree_eval(tree->lnode);
  853.     d = cos((double)force_number(tmp));
  854.     free_temp(tmp);
  855.     return tmp_number((AWKNUM) d);
  856. }
  857.  
  858. static int firstrand = 1;
  859. static char state[256];
  860.  
  861. #ifndef WIN32
  862. #define    MAXLONG    2147483647    /* maximum value for long int */
  863. #endif
  864.  
  865. /* ARGSUSED */
  866. NODE *
  867. do_rand(tree)
  868. NODE *tree;
  869. {
  870.     if (firstrand) {
  871.         (void) initstate((unsigned) 1, state, sizeof state);
  872.         srandom(1);
  873.         firstrand = 0;
  874.     }
  875.     return tmp_number((AWKNUM) random() / MAXLONG);
  876. }
  877.  
  878. NODE *
  879. do_srand(tree)
  880. NODE *tree;
  881. {
  882.     NODE *tmp;
  883.     static long save_seed = 0;
  884.     long ret = save_seed;    /* SVR4 awk srand returns previous seed */
  885.  
  886.     if (firstrand)
  887.         (void) initstate((unsigned) 1, state, sizeof state);
  888.     else
  889.         (void) setstate(state);
  890.  
  891.     if (!tree)
  892.         srandom((int) (save_seed = (long) time((time_t *) 0)));
  893.     else {
  894.         tmp = tree_eval(tree->lnode);
  895.         srandom((int) (save_seed = (long) force_number(tmp)));
  896.         free_temp(tmp);
  897.     }
  898.     firstrand = 0;
  899.     return tmp_number((AWKNUM) ret);
  900. }
  901.  
  902. NODE *
  903. do_match(tree)
  904. NODE *tree;
  905. {
  906.     NODE *t1;
  907.     int rstart;
  908.     AWKNUM rlength;
  909.     Regexp *rp;
  910.  
  911.     t1 = force_string(tree_eval(tree->lnode));
  912.     tree = tree->rnode->lnode;
  913.     rp = re_update(tree);
  914.     rstart = research(rp, t1->stptr, 0, t1->stlen, 1);
  915.     if (rstart >= 0) {    /* match succeded */
  916.         rstart++;    /* 1-based indexing */
  917.         rlength = REEND(rp, t1->stptr) - RESTART(rp, t1->stptr);
  918.     } else {        /* match failed */
  919.         rstart = 0;
  920.         rlength = -1.0;
  921.     }
  922.     free_temp(t1);
  923.     unref(RSTART_node->var_value);
  924.     RSTART_node->var_value = make_number((AWKNUM) rstart);
  925.     unref(RLENGTH_node->var_value);
  926.     RLENGTH_node->var_value = make_number(rlength);
  927.     return tmp_number((AWKNUM) rstart);
  928. }
  929.  
  930. static NODE *
  931. sub_common(tree, global)
  932. NODE *tree;
  933. int global;
  934. {
  935.     register char *scan;
  936.     register char *bp, *cp;
  937.     char *buf;
  938.     int buflen;
  939.     register char *matchend;
  940.     register int len;
  941.     char *matchstart;
  942.     char *text;
  943.     int textlen;
  944.     char *repl;
  945.     char *replend;
  946.     int repllen;
  947.     int sofar;
  948.     int ampersands;
  949.     int matches = 0;
  950.     Regexp *rp;
  951.     NODE *s;        /* subst. pattern */
  952.     NODE *t;        /* string to make sub. in; $0 if none given */
  953.     NODE *tmp;
  954.     NODE **lhs = &tree;    /* value not used -- just different from NULL */
  955.     int priv = 0;
  956.     Func_ptr after_assign = NULL;
  957.  
  958.     tmp = tree->lnode;
  959.     rp = re_update(tmp);
  960.  
  961.     tree = tree->rnode;
  962.     s = tree->lnode;
  963.  
  964.     tree = tree->rnode;
  965.     tmp = tree->lnode;
  966.     t = force_string(tree_eval(tmp));
  967.  
  968.     /* do the search early to avoid work on non-match */
  969.     if (research(rp, t->stptr, 0, t->stlen, 1) == -1 ||
  970.         (RESTART(rp, t->stptr) >= (char) t->stlen) && (matches = 1)) {
  971.         free_temp(t);
  972.         return tmp_number((AWKNUM) matches);
  973.     }
  974.  
  975.     if (tmp->type == Node_val)
  976.         lhs = NULL;
  977.     else
  978.         lhs = get_lhs(tmp, &after_assign);
  979.     t->flags |= STRING;
  980.     /*
  981.      * create a private copy of the string
  982.      */
  983.     if (t->stref > 1 || (t->flags & PERM)) {
  984.         unsigned int saveflags;
  985.  
  986.         saveflags = t->flags;
  987.         t->flags &= ~MALLOC;
  988.         tmp = dupnode(t);
  989.         t->flags = saveflags;
  990.         t = tmp;
  991.         priv = 1;
  992.     }
  993.     text = t->stptr;
  994.     textlen = t->stlen;
  995.     buflen = textlen + 2;
  996.  
  997.     s = force_string(tree_eval(s));
  998.     repl = s->stptr;
  999.     replend = repl + s->stlen;
  1000.     repllen = replend - repl;
  1001.     emalloc(buf, char *, buflen, "do_sub");
  1002.     ampersands = 0;
  1003.     for (scan = repl; scan < replend; scan++) {
  1004.         if (*scan == '&') {
  1005.             repllen--;
  1006.             ampersands++;
  1007.         } else if (*scan == '\\' && *(scan+1) == '&')
  1008.             repllen--;
  1009.     }
  1010.  
  1011.     bp = buf;
  1012.     for (;;) {
  1013.         matches++;
  1014.         matchstart = t->stptr + RESTART(rp, t->stptr);
  1015.         matchend = t->stptr + REEND(rp, t->stptr);
  1016.  
  1017.         /*
  1018.          * create the result, copying in parts of the original
  1019.          * string 
  1020.          */
  1021.         len = matchstart - text + repllen
  1022.               + ampersands * (matchend - matchstart);
  1023.         sofar = bp - buf;
  1024.         while (buflen - sofar - len - 1 < 0) {
  1025.             buflen *= 2;
  1026.             erealloc(buf, char *, buflen, "do_sub");
  1027.             bp = buf + sofar;
  1028.         }
  1029.         for (scan = text; scan < matchstart; scan++)
  1030.             *bp++ = *scan;
  1031.         for (scan = repl; scan < replend; scan++)
  1032.             if (*scan == '&')
  1033.                 for (cp = matchstart; cp < matchend; cp++)
  1034.                     *bp++ = *cp;
  1035.             else if (*scan == '\\' && *(scan+1) == '&') {
  1036.                 scan++;
  1037.                 *bp++ = *scan;
  1038.             } else
  1039.                 *bp++ = *scan;
  1040.         if (global && matchstart == matchend && matchend < text + textlen - 1) {
  1041.             *bp++ = *text;
  1042.             matchend++;
  1043.         }
  1044.         textlen = text + textlen - matchend;
  1045.         text = matchend;
  1046.         if (!global || textlen <= 0 ||
  1047.             research(rp, t->stptr, text-t->stptr, textlen, 1) == -1)
  1048.             break;
  1049.     }
  1050.     sofar = bp - buf;
  1051.     if (buflen - sofar - textlen - 1) {
  1052.         buflen = sofar + textlen + 2;
  1053.         erealloc(buf, char *, buflen, "do_sub");
  1054.         bp = buf + sofar;
  1055.     }
  1056.     for (scan = matchend; scan < text + textlen; scan++)
  1057.         *bp++ = *scan;
  1058.     textlen = bp - buf;
  1059.     free(t->stptr);
  1060.     t->stptr = buf;
  1061.     t->stlen = textlen;
  1062.  
  1063.     free_temp(s);
  1064.     if (matches > 0 && lhs) {
  1065.         if (priv) {
  1066.             unref(*lhs);
  1067.             *lhs = t;
  1068.         }
  1069.         if (after_assign)
  1070.             (*after_assign)();
  1071.         t->flags &= ~(NUM|NUMBER);
  1072.     }
  1073.     return tmp_number((AWKNUM) matches);
  1074. }
  1075.  
  1076. NODE *
  1077. do_gsub(tree)
  1078. NODE *tree;
  1079. {
  1080.     return sub_common(tree, 1);
  1081. }
  1082.  
  1083. NODE *
  1084. do_sub(tree)
  1085. NODE *tree;
  1086. {
  1087.     return sub_common(tree, 0);
  1088. }
  1089.  
  1090. #ifdef GFMT_WORKAROUND
  1091.     /*
  1092.      *    printf's %g format [can't rely on gcvt()]
  1093.      *        caveat: don't use as argument to *printf()!
  1094.      */
  1095. char *
  1096. gfmt(g, prec, buf)
  1097. double g;    /* value to format */
  1098. int prec;    /* indicates desired significant digits, not decimal places */
  1099. char *buf;    /* return buffer; assumed big enough to hold result */
  1100. {
  1101.     if (g == 0.0) {
  1102.         (void) strcpy(buf, "0");    /* easy special case */
  1103.     } else {
  1104.         register char *d, *e, *p;
  1105.  
  1106.         /* start with 'e' format (it'll provide nice exponent) */
  1107.         if (prec < 1) prec = 1;        /* at least 1 significant digit */
  1108.         (void) sprintf(buf, "%.*e", prec - 1, g);
  1109.         if ((e = strchr(buf, 'e')) != 0) {    /* find exponent  */
  1110.             int exp = atoi(e+1);        /* fetch exponent */
  1111.             if (exp >= -4 && exp < prec) {    /* per K&R2, B1.2 */
  1112.                 /* switch to 'f' format and re-do */
  1113.                 prec -= (exp + 1);    /* decimal precision */
  1114.                 (void) sprintf(buf, "%.*f", prec, g);
  1115.                 e = buf + strlen(buf);
  1116.             }
  1117.             if ((d = strchr(buf, '.')) != 0) {
  1118.                 /* remove trailing zeroes and decimal point */
  1119.                 for (p = e; p > d && *--p == '0'; ) continue;
  1120.                 if (*p == '.') --p;
  1121.                 if (++p < e)    /* copy exponent and NUL */
  1122.                     while ((*p++ = *e++) != '\0') continue;
  1123.             }
  1124.         }
  1125.     }
  1126.     return buf;
  1127. }
  1128. #endif    /* GFMT_WORKAROUND */
  1129.